﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Microsoft.Practices.Unity;
using System.ServiceModel.Activation;
using System.Diagnostics;
using Skynet.BusinessEntities;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting;
using IronPython.Hosting;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Skynet.BusinessLogic.Constants;
using Infrastructure.Aspect.Services.XmlDataQueries;
using System.Threading;
namespace Skynet.BusinessLogic.BusinessComponents
{  
	[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode= InstanceContextMode.PerCall)]
	public partial class BCExams : IBCExams, IBCQExams
	{
		[Dependency]
		public DataAccess.IExamCategoryRepository ExamCategoryRepository {protected get; set; }

		[Dependency]
		public DataAccess.IExamRepository ExamRepository { get; set; }

		[Dependency]
		public DataAccess.IQuestionRepository QuestionRepository { get; set; }

		[Dependency]
		public DataAccess.IAlternativeRepository AlternativeRepository { get; set; }

		[Dependency]
		public DataAccess.IExamByCustomerRepository ExamByCustomerRepository { get; set; }

		[Dependency]
		public DataAccess.IAlternativeExpEvaluationRepository AlternativeExpEvaluationRepository { get; set; }


		[Dependency]
		public IXmlDataQueriesService XmlDataQueriesService { get; set; }
		
		public void MaintenanceExams(Exam exam)
		{
			

			switch (exam.ChangeTracker.State)
			{
				case ObjectState.Unchanged:
					break;
				case ObjectState.Added:
					this.ExamRepository.Add(exam);                  
					break;
				case ObjectState.Modified:
					this.ExamRepository.Update(exam);
					break;
				case ObjectState.Deleted:
					this.ExamRepository.Delete(exam);
					break;
				default:
					break;
			}
			foreach (var item in exam.Questions)
			{
				switch (item.State)
				{
					case ObjectState.Unchanged:
						break;
					case ObjectState.Added:
						item.ExamId = exam.Id;
						this.QuestionRepository.Add(item);
						break;
					case ObjectState.Modified:
						break;
					case ObjectState.Deleted:
						break;
					default:
						break;
				}
				foreach (var alt in item.Alternatives)
				{
					switch (alt.State)
					{
						case ObjectState.Unchanged:
							break;
						case ObjectState.Added:
							alt.QuestionId = item.Id;
							this.AlternativeRepository.Add(alt);
							break;
						case ObjectState.Modified:
							break;
						case ObjectState.Deleted:
							break;
						default:
							break;
					}                    
				}
			}


			exam.AcceptChanges();  
		}


        //[OperationBehavior(TransactionScopeRequired=true,  TransactionAutoComplete = true)]
		public void MaintenanceExamCategories(IEnumerable<ExamCategory> items)
		{            
			foreach (var item in items)
			{                
                this.ExamCategoryRepository.Maintenance(item);               
			}            
		}
		public void ActivateExam(Guid CustomerId, Guid ExamId, short Duration, DateTime validFrom, DateTime validTo)
		{ 
			var exc = new BusinessEntities.ExamByCustomer(); 
			exc.Id= Guid.NewGuid();
			exc.CustomerId = CustomerId; 
			exc.ExamId = ExamId; 
			exc.Duration = Duration; 
			exc.Score = 0;
			exc.Status = (short)BusinessEntities.ExamActivationStatus.Active;
			exc.ValidFrom= validFrom; 
			exc.ValidTo = validTo;

			this.ExamByCustomerRepository.Add(exc);
			var questions =  this.QuestionRepository.DesignQuestionsByExamId(ExamId);
			foreach (var item in questions)
			{
				item.Alternatives = this.AlternativeRepository.DesignAlternativesByQuestionId(item.Id);
			}
			foreach (var question in questions)
			{
				question.CustomerQuestionId = Guid.NewGuid();
				question.CustomerExamId = exc.Id;
				this.QuestionRepository.AddRuntimeQuestion(question);
				foreach (var alt in question.Alternatives)
				{
					alt.CustomerAlternativeId = Guid.NewGuid();
					alt.CustomerQuestionId = question.CustomerQuestionId;
					this.AlternativeRepository.AddRuntimeAlternative(alt);                    
				}                
			}

		}
		
		public void FinishExam(Guid ExamByCustomerId)
		{


			ScriptEngine engine = Python.CreateEngine();
			var exam = this.ExamByCustomerRepository.GetRuntimeByCustomerExamId(ExamByCustomerId);
			var questions = this.QuestionRepository.RuntimeByCustomerExamId(ExamByCustomerId);
			foreach (var item in questions)
			{
				var question = item;
				this.QuestionRepository.LoadRuntimeQuestion(ref question);
				question.Alternatives = this.AlternativeRepository.CalificationAlternativesByCustomerQuestionId(question.CustomerQuestionId);                                
			}
			double examscore= 0;

			foreach (var question in questions)
			{
				double questionscore= 0;
				foreach (var alternative in question.Alternatives)
				{
					var input = this.AlternativeExpEvaluationRepository.GetEvaluationExpression(alternative.EvaluationKey());
					if (!string.IsNullOrWhiteSpace(input))
					{	
						ScriptScope scope = engine.CreateScope();
						scope.SetVariable("Exam", exam);
						scope.SetVariable("Question", question);
						scope.SetVariable("Alternative", alternative);                        						
						ScriptSource source = engine.CreateScriptSourceFromString(input, SourceCodeKind.Statements);
						source.Execute(scope);
						questionscore += scope.GetVariable<double>("Score");
						examscore += scope.GetVariable<double>("Score");    
					}                    
					else
					{
						var btarget = alternative as BoolAlternative;
						if (btarget.Answer == btarget.CustomerAnswer)
						{
							questionscore += btarget.Score;
							examscore += btarget.Score;
						}
					}                                     
				}                
				this.QuestionRepository.UpdateScore(question.CustomerQuestionId, questionscore);
			}
			this.ExamByCustomerRepository.UpdateCurrentTime(ExamByCustomerId);
			this.ExamByCustomerRepository.UpdateScore(ExamByCustomerId, examscore);
			this.ExamByCustomerRepository.UpdateStatus(ExamByCustomerId, ExamActivationStatus.Finish);
		}

		
		public void AcceptExam(Guid ExamByCustomerId)
		{               
			var ExamByCustomer = this.ExamByCustomerRepository.GetOne(ExamByCustomerId);
			ExamByCustomer.Status = (short)ExamActivationStatus.Inprogress;
			ExamByCustomer.StartTime = DateTime.Now;
			ExamByCustomer.CurrentTime = DateTime.Now;
			this.ExamByCustomerRepository.Update(ExamByCustomer);         
		}
	
	
		public void MaintenanceQuestions(MaintenanceQuestionsOptions option=   MaintenanceQuestionsOptions.CUD, BaseQuestion question= null)
		{
			switch (option)
			{
				case MaintenanceQuestionsOptions.CUD:

					switch (question.State)
					{
						case ObjectState.Added:
							this.QuestionRepository.Add(question);
						break;
						case ObjectState.Modified:
							this.QuestionRepository.Update(question);
						break;
						default:
								
						break;
					}

					break;
				case MaintenanceQuestionsOptions.UReview:
					this.ExamByCustomerRepository.UpdateCurrentTime(question.CustomerExamId);
					this.QuestionRepository.UpdateReview(question.CustomerQuestionId, question.Review);
					break;
				default:
					break;
			}            
		}


		public void MaintenanceAlternative(MaintenanceAlternativeOptions options = MaintenanceAlternativeOptions.CUD, BaseAlternative alternative = null)
		{
			switch (options)
			{
				case MaintenanceAlternativeOptions.CUD:

					switch (alternative.State)
					{
						case ObjectState.Unchanged:
							break;
						case ObjectState.Added:
							this.AlternativeRepository.Add(alternative);
							break;
						case ObjectState.Modified:
							this.AlternativeRepository.Update(alternative);
							break;
						case ObjectState.Deleted:
							break;
						default:
							break;
					}

					break;
				case MaintenanceAlternativeOptions.UCustomerAnswer:
					this.AlternativeRepository.UpdateCustomerAnswer(alternative);
					break;
				default:
					break;
			}
		}

		

	
		
	
	}
}
